"""
1．实参和形参
    定义函数时，圆括号内的参数为形参；调用函数时，圆括号内的参数为实参，根据参数的不同数据类型，将实参的值或引用传递给形参。
    在Python中，函数参数的数据类型可分为不可变数据类型（如整数、浮点数、字符串、元组等）和可变数据类型（如列表、字典、集合等）。当参数的数据类型为不可变数据类型时，在函数内直接修改形参的值不会影响实参
"""
"""
【例5-4】   阅读下面程序，分析输出结果。
【参考代码】
【程序说明】  从运行结果可以看出，在函数内修改了形参a的值，但是当函数运行结束后，实参a的值并没有改变。但当参数的数据类型为可变数据类型时，在函数内使用下标或其他方式增加、删除或修改元素时，实参也会相应地修改。
"""
# def change(a):
#     a = 10
#     print('函数内a =', a)
#
# a = 2
# change(a)  # 10
# print('函数外a =', a) # 2
"""
【例5-5】   阅读下面程序，分析输出结果。
【参考代码】
【程序说明】  从运行结果可以看出，在函数内修改了形参mylist的元素，当函数运行结束后，实参mylist的值也修改了。
"""
# def change(mylist):
#     mylist.append([1, 2, 3, 4])
#     print('函数内mylist = ', mylist)
#
#
# mylist = [10, 20, 30]
# print('调用函数前，函数外mylist = ', mylist)
# change(mylist) #[10,20,30,[1,2,3,4]]
# print('调用函数后，函数外mylist = ', mylist)
"""
2．参数类型
    在Python中，函数有多种参数类型，包括位置参数、默认值参数、关键字参数和不定长参数。
1）位置参数：
    位置参数是比较常用的形式，调用函数时，实参和形参的顺序应一致，且实参和形参的数量必须相同。
"""
"""
【例5-6】  定制问候语。对不同的人说不同的问候语。
【问题分析】  定义函数greet(name, say)，其中，name表示人名，say表示问候语。
【参考代码】
【程序说明】 当第一次调用greet()函数时，将实参“小蓝”和“你好！”分别传递给形参name和say，实现输出。当第二次调用greet()函数时，将实参“hello！”和“小舞”分别传递给形参name和say，虽然也可以正常输出，但实参和形参的含义不一致，将会影响数据的理解和使用，因此，位置参数的实参和形参的顺序须一致。当第三次调用greet()函数时，实参和形参的数量不同，程序运行到该条语句时提示错误信息（缺少要求的位置参数say）
"""


# def greet(name, say):
#     print(name, say)
#
#
# greet('小蓝', '你好！')
# greet('hello！', '小舞')
# greet('小明')
"""
2）默认值参数：
    在定义函数时，可以为函数的参数设置默认值，此参数称为默认值参数。在调用带默认值参数的函数时，可以不用为默认值参数传值，此时函数将会直接使用函数定义时设置的默认值，也可以通过显式赋值来替换其默认值。定义带有默认值参数函数的基本语法格式如下。
语法：
    def 函数名(……,形参名=默认值):
        函数体
提示：
       在定义带有默认值参数的函数时，默认值参数必须出现在函数形参列表的最右端，否则会提示语法错误。例如，下面函数的定义是错误的。
       def f(a = 1, b, c = 3):
              print(a, b, c)
       还可使用“函数名.__defaults__”查看函数所有默认值参数的当前值，其返回值为一个元组，其中的元素依次表示每个默认值参数的当前值
"""
"""
【例5-7】  使用不可变数据类型设置默认问候语。
【参考代码】
【程序说明】 多次调用函数且不为默认值参数传递值时，默认值参数只在定义时进行一次解释和初始化，而对于列表、字典等可变数据类型的默认值参数，可能会导致逻辑错误。因此，一般来说，要避免使用列表、字典、集合或其他可变数据类型作为函数参数的默认值
"""
#
# def greet(name, say = 'Hi!'):  # 设置默认问候语为“hi！”
#     print(name, say)
#
# # print(greet.__defaults__)  # 输出函数默认值参数
# greet('小蓝', '你好！')
# greet('小舞', 'hello！')
# greet('小红')
# greet('小明')

"""
【例5-8】   使用可变数据类型设置默认问候语。
【参考代码】
【程序说明】   
使用列表作为默认值参数，且连续多次调用该函数而不给该参数传值时，再次调用将保留上一次调用结果。因此，执行语句“greet('小红')”时，输出的列表say中包含两个“见到你很开心”，即在上一次调用结果的基础上增加了同一元素。
此外，如果在定义函数时某个参数的默认值为一个变量，那么参数的默认值只取决于函数定义时该变量的值。

"""
# def greet(name, say=['hi！']):		#使用列表设置默认问候语
#     say.append('见到你很开心')			#列表添加元素
#     print(name, say)
# greet('小蓝', ['你好！'])
# greet('小舞', ['hello！'])
# greet('小明')
# greet('小红')

"""
【例5-9】   使用变量设置默认问候语。
【参考代码】 
【程序说明】函数的默认值参数只会初始化一次，即在函数定义时就确定值，所以，在定义函数greet()时，s的值为“hi！”，因此输出为“小蓝 hi！”。
"""
# s = 'hi！'
# def greet(name, say=s):
#     print(name, say)
# s = '你好！'
# greet('小蓝')

"""
3）关键字参数
    关键字参数是指调用函数时按参数名传递值。使用关键字参数允许函数调用时参数的顺序与定义时不一致，Python解释器能够使用参数名匹配参数值。
【例5-3】 使用关键字参数设置问候语。
【参考代码】
"""
# def greet(name, say):
#     print(name, say)
# greet('你好！', '小蓝')
# greet(say='hello！', name='小舞')

"""
4）不定长参数:通常在定义一个函数时，若希望函数能够处理比定义时更多的参数，此时可在函数中使用“*”或“**”符号表示不定长参数，其基本语法格式如下。
    
语法：
    def 函数名([形参列表,] *args, **kwargs):
        函数体
         1、*args - 接收任意数量的位置参数，将传入的多个位置参数打包成元组(tuple)，参数名不一定是args，但约定俗成用这个名称，可以接受0个或多个参数
          2、**kwargs - 接收任意数量的关键字参数，将传入的关键字参数打包成字典(dictionary)，参数名不一定是kwargs，但约定俗成用这个名称，可以接受0个或多个关键字参数
【例5-11】使用不定长参数同时和多人说问候语。
【参考代码】
【程序说明】 在调用greet()函数时，传入多个值，这些值会自左往右依次匹配函数定义时的参数，首先将“hi！”传递给say，接着将“'小蓝', '小舞'”组成一个元组，传递给names，最后将“小红='你好！', 小明='hello！'”转换为字典传递给name_say。
"""
def greet(say, *names, **name_say):
    print('say：', say)
    print('names：', names)
    print('name_say：', name_say)
    for name in names:
        print(name, say)
    for key in name_say.keys():
        print(key, name_say[key])
greet('hi！', '小蓝', '小舞', 小红='你好！', 小明='hello！')
# greet('hi！','小蓝','小蓝','小蓝','小蓝','小蓝',小蓝='mingzi',小明='age')
